#pragma once

#include "KnowledgeBaseWriterInterface.h"
#include "Localization.h"
#include "TextStreamInterface.h"
#include <vector>

class KnowledgeBaseWriterText;
typedef Factory < KnowledgeBaseWriterInterface >::CastedPtr < KnowledgeBaseWriterText > KnowledgeBaseWriterTextPtr;

class KnowledgeBaseWriterText
: public KnowledgeBaseWriterInterface
{
	friend class Factory < KnowledgeBaseWriterInterface >;
	friend class FieldWriter;
	
public:
	static KnowledgeBaseWriterInterfacePtr Spawn 
		( TextStreamInterfacePtr textStream
		, KnowledgeBaseWriterTextLocalizationInterfacePtr writerLocalization
		);
	static void CheckInnocence ();
	
private:
	class FieldWriterInterface;
	typedef Factory < FieldWriterInterface >::Ptr FieldWriterInterfacePtr;
	
	class FieldWriter;
	typedef Factory < FieldWriterInterface >::CastedPtr < FieldWriter > FieldWriterPtr;

	class FieldWriterInterface
	{
	public:
		virtual ~FieldWriterInterface () {}
		virtual void CalculateWidth () = 0;
		virtual void TitleBarPrepare () = 0;
		virtual void TitleBarFetchNextLine () = 0;
		virtual bool TitleBarCheck () = 0;
		virtual void TitleBarWrite () = 0;
		virtual void WriteDelimiter () = 0;
		virtual void WriteMemoryElement ( int globalAddress ) = 0;
	};
	
	class FieldWriter
	: public FieldWriterInterface
	{
		friend class Factory < FieldWriterInterface >;
		friend class KnowledgeBaseWriterText;
	public:
		template < class WRITER >
		static FieldWriterInterfacePtr Spawn ( KnowledgeBaseWriterTextPtr argWriter )
		{
			Factory < FieldWriterInterface >::CastedPtr < WRITER > fieldWriter = factory.CreateNewObject < WRITER > (); 
			fieldWriter->writer = argWriter;
			return fieldWriter;
		}
	protected:
		FieldWriter ();
		KnowledgeBaseMemoryInterfacePtr Memory ();
		KnowledgeBaseWriterTextLocalizationInterfacePtr Localization ();
		
	private:
		virtual void CalculateWidth ();
		virtual void TitleBarPrepare ();
		virtual void TitleBarFetchNextLine ();
		virtual bool TitleBarCheck ();
		virtual void TitleBarWrite ();
		virtual void WriteDelimiter ();
		virtual void WriteMemoryElement ( int globalAddress );
	private:
		virtual std::string GetLocalization ( KnowledgeBaseWriterTextLocalizationInterfacePtr localization ) = 0;
		virtual std::string GetElementField ( KnowledgeBaseElementInterfacePtr element, int globalAddress ) = 0;
	private:
		static Factory < FieldWriterInterface > factory;
		KnowledgeBaseWriterTextPtr writer;
		int width;
		std::vector < std::string > title;
		std::string nextLine;
	};
	
#define DECLARE_FIELD_WRITER(name) \
	class FieldWriter_##name \
	: public FieldWriter \
	{ \
		virtual std::string GetLocalization ( KnowledgeBaseWriterTextLocalizationInterfacePtr localization ); \
		virtual std::string GetElementField ( KnowledgeBaseElementInterfacePtr element, int globalAddress ); \
	}
	
	DECLARE_FIELD_WRITER ( SeniorKey );
	DECLARE_FIELD_WRITER ( SeniorType );
	DECLARE_FIELD_WRITER ( LexemText );
	DECLARE_FIELD_WRITER ( UpperBranch );
	DECLARE_FIELD_WRITER ( LowerBranch );
	DECLARE_FIELD_WRITER ( NextLevel );
	DECLARE_FIELD_WRITER ( Synonym );
	DECLARE_FIELD_WRITER ( AdjacentAscending );
	DECLARE_FIELD_WRITER ( AdjacentDescending );
	DECLARE_FIELD_WRITER ( BeforeAdjacentAscending );
	DECLARE_FIELD_WRITER ( BeforeAdjacentDescending );
	DECLARE_FIELD_WRITER ( GreaterAscending );
	DECLARE_FIELD_WRITER ( GreaterDescending );
	DECLARE_FIELD_WRITER ( LesserAscending );
	DECLARE_FIELD_WRITER ( LesserDescending );
	
#undef DECLARE_FIELD_WRITER
	
	KnowledgeBaseWriterText ();
	virtual ~KnowledgeBaseWriterText ();
	virtual void Write ( KnowledgeBaseMemoryInterfacePtr memory );
	void CalculateGlobalAddressWidth ();
	void WriteDelimiter ();
	void WriteTitleBar ();
	void WriteMemoryElement ( int globalAddress );
	bool TitleBarCheckFieldWriters ();
	
private:
	static Factory < KnowledgeBaseWriterInterface > factory;
	TextStreamInterfacePtr stream;
	KnowledgeBaseWriterTextLocalizationInterfacePtr localization;
	KnowledgeBaseMemoryInterfacePtr memory;
	int globalAddressWidth;
	std::vector < FieldWriterInterfacePtr > fieldWriters;
};
